﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel;

namespace TA.DotNetUtils
{
	public class SimpleIdValue<I, T, P> : IIdValue//, IConvertible
		where I : struct
		where T : IHasId<I>, IFromDataRow, IFromDataSet, new()
		where P : BaseProvider<I, T>, new()
	{
		I _id;
		T _value;

		public SimpleIdValue(I id)
		{
			Id = id;
		}
		public SimpleIdValue(T value)
		{
			Value = value;
		}
		public virtual I Id
		{
			get
			{
				return _id;
			}
			set
			{
				if (!object.Equals(_id, value))
				{
					_id = value;
					_value = default(T);
				}
			}
		}
		public T Value
		{
			get
			{
				if (_value == null)
				{
					P p = new P();
					_value = p.Get(this._id);
				}
				return _value;
			}
			set
			{
				if (value == null) throw new ArgumentNullException();
				Id = (I)value.GenericId;
				_value = value;
			}
		}
		public bool HasValue
		{
			get
			{
				return _value != null;
			}
		}
		public object GenericId
		{
			get
			{
				return Id;
			}
			set
			{
				if (value is I)
					Id = (I)value;
				else
					throw new ArgumentException();
			}
		}
		public static implicit operator SimpleIdValue<I, T, P>(I id)
		{
			return new SimpleIdValue<I, T, P>(id);
		}
		public static implicit operator SimpleIdValue<I, T, P>(T value)
		{
			if (value == null)
				return null;
			return new SimpleIdValue<I, T, P>(value);
		}
		public static implicit operator I(SimpleIdValue<I, T, P> idValue)
		{
			if (idValue == null) return default(I);
			return idValue.Id;
		}
		public static implicit operator I?(SimpleIdValue<I, T, P> idValue)
		{
			if (idValue == null) return null;
			return idValue.Id;
		}
		public static implicit operator SimpleIdValue<I, T>(SimpleIdValue<I, T, P> idValue)
		{
			if (idValue == null) return null;
			if (idValue.HasValue)
				return idValue.Value;
			return idValue.Id;
		}
		public static implicit operator SimpleIdValue<I, T, P>(SimpleIdValue<I, T> idValue)
		{
			if (idValue == null) return null;
			if (idValue.HasValue)
				return idValue.Value;
			return idValue.Id;
		}
		public override string ToString()
		{
			return _id.ToString();
		}
		public override int GetHashCode()
		{
			return Id.GetHashCode();
		}
		public bool Equals(SimpleIdValue<I, T, P> obj)
		{
			return obj != null && this.Id.Equals(obj.Id);
		}
		public override bool Equals(object obj)
		{
			if (obj is SimpleIdValue<I, T> && this.Id.Equals(((SimpleIdValue<I, T>)obj).Id))
				return true;
			if (obj is SimpleIdValue<I, T, P> && this.Id.Equals(((SimpleIdValue<I, T, P>)obj).Id))
				return true;
			if (obj is I && object.Equals(this.Id, obj))
				return true;
			if (obj is T && object.Equals(this.Id, ((T)obj).Id))
				return true;
			return false;
		}

		#region IIdValue Members

		public object GenericValue
		{
			get
			{
				return Value;
			}
			set
			{
				Value = (T)value;
			}
		}

		#endregion
	}
	/// <summary>
	/// Secure id value.
	/// </summary>
	/// <typeparam name="I">Id</typeparam>
	/// <typeparam name="T">Type</typeparam>
	/// <typeparam name="P">Provider</typeparam>
	/// <typeparam name="U">User</typeparam>
	//public class SimpleIdValue<I, T, P, U> : IHasGenericId, IIdValue//, IConvertible
	//  where I : struct
	//  where T : IHasId<I>, IFromDataRow, IFromDataSet, new()
	//  where P : BaseProvider<I, T, U>, new()
	//  where U : IHasGenericId
	//{
	//  I _id;
	//  T _value;

	//  public SimpleIdValue(I id)
	//  {
	//    Id = id;
	//  }
	//  public SimpleIdValue(T value)
	//  {
	//    Value = value;
	//  }
	//  public virtual I Id
	//  {
	//    get
	//    {
	//      return _id;
	//    }
	//    set
	//    {
	//      if (!object.Equals(_id, value))
	//      {
	//        _id = value;
	//        _value = default(T);
	//      }
	//    }
	//  }
	//  public T Value
	//  {
	//    get
	//    {
	//      if (_value == null)
	//      {
	//        P p = new P();
	//        _value = p.Get(this._id);
	//      }
	//      return _value;
	//    }
	//    set
	//    {
	//      if (value == null) throw new ArgumentNullException();
	//      Id = (I)value.GenericId;
	//      _value = value;
	//    }
	//  }
	//  public bool HasValue
	//  {
	//    get
	//    {
	//      return _value != null;
	//    }
	//  }
	//  public object GenericId
	//  {
	//    get
	//    {
	//      return Id;
	//    }
	//    set
	//    {
	//      if (value is I)
	//        Id = (I)value;
	//      else
	//        throw new ArgumentException();
	//    }
	//  }
	//  public static implicit operator SimpleIdValue<I, T, P, U>(I id)
	//  {
	//    return new SimpleIdValue<I, T, P, U>(id);
	//  }
	//  public static implicit operator SimpleIdValue<I, T, P, U>(T value)
	//  {
	//    if (value == null)
	//      return null;
	//    return new SimpleIdValue<I, T, P, U>(value);
	//  }
	//  public static implicit operator I(SimpleIdValue<I, T, P, U> idValue)
	//  {
	//    if (idValue == null) return default(I);
	//    return idValue.Id;
	//  }
	//  public static implicit operator I?(SimpleIdValue<I, T, P, U> idValue)
	//  {
	//    if (idValue == null) return null;
	//    return idValue.Id;
	//  }
	//  public static implicit operator T(SimpleIdValue<I, T, P, U> idValue)
	//  {
	//    if (idValue == null) return default(T);
	//    return idValue.Value;
	//  }
	//  public override string ToString()
	//  {
	//    return _id.ToString();
	//  }
	//  public override int GetHashCode()
	//  {
	//    return Id.GetHashCode();
	//  }
	//  public override bool Equals(object obj)
	//  {
	//    if (obj is SimpleIdValue<I, T> && object.Equals(this.Id, ((SimpleIdValue<I, T>)obj).Id))
	//      return true;
	//    if (obj is I && object.Equals(this.Id, obj))
	//      return true;
	//    if (obj is T && object.Equals(this.Id, ((T)obj).Id))
	//      return true;
	//    return false;
	//  }

	//  #region IIdValue Members

	//  public object GenericValue
	//  {
	//    get
	//    {
	//      return Value;
	//    }
	//    set
	//    {
	//      Value = (T)value;
	//    }
	//  }

	//  #endregion
	//}
}
